import base64
import hashlib
import json
import time

from utils import *

LOGIN_IN = "/Action/login"
CALL_API = "/Action/call"


class IKuai:
    instance = None  # 单例模式的实例
    _is_init = False
    # l2tp_client
    client_type = "pptp_client"

    def __new__(cls, self=None, *args, **kwargs):
        if cls.instance is None:
            cls.instance = super().__new__(cls)
        return cls.instance

    def __init__(self):
        if self._is_init is False:
            self.ip_id = {}
            self.l2tp_data = None
            self.keep = {}
            res = json.loads(self.insert_route_info())
            if res["ErrMsg"] == "Success" and res["Result"] == 10000:
                win_log("Ikuai系统登录成功.....")
            print("res", res)
            self._is_init = True
            DkGlobal().ikuai = self

    def insert_route_info(self, port=80):
        if DkGlobal().window != None:
            ikuai = DkGlobal().window.ikuai
        else:
            ikuai = {
                "ip": "192.168.9.1",
                "username": "admin",
                "password": "lhblm520",
            }
        win_log("登录Ikuai系统....")
        self.ip = ikuai['ip']
        self.port = port
        self.username = ikuai['username']
        self.password = ikuai['password']
        self.base_url = f"http://{self.ip}:{self.port}"
        self.__encode_password__()
        data = {
            "username": self.username,
            "passwd": self.md5_password,
            "pass": self.__encode_pass__(),
            "remember_password": "",
        }
        self.session = requests.Session()
        self.session.headers.update(
            {
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3",
                "Accept": "application/json",
                "Content-type": "application/json;charset=utf-8",
                "Accept-Language": "zh-CN",
            }
        )
        self.call_url = self.base_url + CALL_API
        login_in_status = self.session.post(
            f"{self.base_url}{LOGIN_IN}", data=json.dumps(data)
        )
        return login_in_status.text

    def get_cpu_info(self):
        payload = {
            "func_name": "sysstat",
            "action": "show",
            "param": {"TYPE": "verinfo,cpu,memory,stream,cputemp"},
        }
        url = self.base_url + CALL_API
        resp = self.session.post(url, None, payload)
        return resp

    def __encode_password__(self):
        md5 = hashlib.md5()
        md5.update(self.password.encode())
        hash_value = md5.hexdigest()
        self.md5_password = hash_value

    def __encode_pass__(self) -> str:
        d = ("salt_11" + self.password).encode("ASCII")
        encode_pass = base64.b64encode(d).decode()
        return encode_pass

    # 更新IP地址
    def refresh_ip(self, android, check=False, again=False, count=0):
        l2tp_id = android['l2tp']['id']
        print(l2tp_id)
        json_data = {"func_name": self.client_type, "action": "down", "param": {"id": f"{l2tp_id}"}}
        # 禁用
        self.session.post(self.base_url + CALL_API, None, json_data)
        win_log(f"设备{android['Name']} 【禁用】动态IP成功", '', android['Name'])
        time.sleep(3)
        json_data['action'] = 'up'
        # 启用
        self.session.post(self.base_url + CALL_API, None, json_data)
        win_log(f"设备{android['Name']} 重拨动态IP成功", '', android['Name'])
        time.sleep(2)
        self.keep[l2tp_id] = None
        if check:
            check_time = 0
            while True:
                if check_time > 6:
                    if again == True and count <= 3:
                        self.refresh_ip(android, check, again, count + 1)
                    break
                res = self.get_iface_check(android['l2tp']['name'])
                if res == True:
                    break
                else:
                    time.sleep(5)
                    check_time += 1

    def refresh_ip_by_id(self, l2tp_id):
        json_data = {"func_name": self.client_type, "action": "down", "param": {"id": f"{l2tp_id}"}}
        # 禁用
        self.session.post(self.base_url + CALL_API, None, json_data)
        time.sleep(3)
        json_data['action'] = 'up'
        # 启用
        self.session.post(self.base_url + CALL_API, None, json_data)

    def latp_keep(self):
        port_flow_list = self.get_port_flow_list()
        port_data = {}
        for port in port_flow_list:
            if port['enabled'] == 'yes':
                port_data[port['interface']] = True
            else:
                port_data[port['interface']] = False

        while True:
            if DkGlobal().window.running != True:
                break
            l2tps = self.get_l2tp_ip_data()
            for l2tp in l2tps.values():
                if l2tp['name'] not in port_data:
                    # 如果线路多，端口绑定少的情况
                    continue
                if port_data[l2tp['name']] is False :
                    continue
                if l2tp['ip_addr'] == "":
                    if l2tp['id'] in self.keep and self.keep[l2tp['id']] != None and self.keep[l2tp['id']] < int(time.time()) - 60:
                        print(f"自动检测线路没网了-{l2tp['id']}执行重启ip")
                        self.refresh_ip_by_id(l2tp['id'])
                        self.keep[l2tp['id']] = None
                    elif l2tp['id'] not in self.keep or self.keep[l2tp['id']] == None:
                        print(f"首次失败先记录-{l2tp['id']}")
                        self.keep[l2tp['id']] = int(time.time())
                else:
                    self.keep[l2tp['id']] = None
            time.sleep(3)

    # 初始化端口分流数据
    def get_port_flow_data(self):
        json_data = {
            "func_name": "stream_ipport",
            "action": "show",
            "param": {
                "TYPE": "total,data",
                "limit": "0,100",
                "ORDER_BY": "",
                "ORDER": ""
            }
        }
        res_data = {}
        port_res = self.session.post(self.base_url + CALL_API, None, json_data)
        if port_res.status_code == 200:
            port_res = json.loads(port_res.text)
            # print('port_list', port_res)
            win_log("Ikuai获取端口转发列表成功")
            if port_res['Result'] == 30000:
                port_data = port_res['Data']['data']
                for item in port_data:
                    # ip 对应 拨号名称
                    res_data[item['src_addr']] = item['interface']
            else:
                return False
        else:
            return False
        return res_data

    def get_port_flow_list(self):
        json_data = {
            "func_name": "stream_ipport",
            "action": "show",
            "param": {
                "TYPE": "total,data",
                "limit": "0,100",
                "ORDER_BY": "",
                "ORDER": ""
            }
        }
        port_res = self.session.post(self.base_url + CALL_API, None, json_data)
        if port_res.status_code == 200:
            port_res = json.loads(port_res.text)
            # print('port_list', port_res)
            win_log("Ikuai获取端口转发列表成功")
            if port_res['Result'] == 30000:
                port_data = port_res['Data']['data']
                return port_data
                # for item in port_data:
                #     # ip 对应 拨号名称
                #     res_data[item['src_addr']] = item['interface']
            else:
                return False
        else:
            return False

    # pptp_client
    # 初始化IP对应ID
    def get_l2tp_ip_data(self):
        json_data = {
            "func_name": self.client_type,
            "action": "show",
            "param": {
                "TYPE": "total,data",
                "limit": "0,100",
                "ORDER_BY": "",
                "ORDER": ""
            }
        }
        res_data = {}
        l2tp_res = self.session.post(self.base_url + CALL_API, None, json_data)
        if l2tp_res.status_code == 200:
            l2tp_res = json.loads(l2tp_res.text)
            if l2tp_res['Result'] == 30000:
                self.l2tp_data = l2tp_res['Data']['data']
                for item in self.l2tp_data:
                    res_data[item['name']] = item
            else:
                return False
        else:
            return False
        return res_data

    # 获取IP对应ID的字典
    def get_ip_id_list(self):
        res_data = {}
        port_flow_data = self.get_port_flow_data()
        l2tp_ip_data = self.get_l2tp_ip_data()

        for key in port_flow_data.keys():
            item = port_flow_data[key]
            res_data[key] = l2tp_ip_data[item]['id']

        win_log("获取设备IP对应的重拨L2TP_ID成功")
        print("l2tp_ip_data", res_data)
        return res_data

    def get_ip_item_list(self):
        res_data = {}
        port_flow_data = self.get_port_flow_data()
        l2tp_ip_data = self.get_l2tp_ip_data()

        for key in port_flow_data.keys():
            item = port_flow_data[key]
            res_data[key] = l2tp_ip_data[item]
        return res_data

    def get_l2tp_by_id(self, l2tp_id):
        l2tp_data = self.l2tp_data
        if l2tp_data == None:
            l2tp_data = self.get_l2tp_ip_data().values()

        for item in l2tp_data:
            if item['id'] == l2tp_id:
                return item
        return False

    def get_iface_check(self, l2tp_name):
        # l2tp = self.get_l2tp_by_id(l2tp_id)
        # if l2tp == False:
        #     return False
        # interface = l2tp['name']
        json_data = {
            "func_name": "monitor_iface",
            "action": "show",
            "param": {
                "TYPE": "iface_check"
            }
        }
        iface_check_res = self.session.post(self.base_url + CALL_API, None, json_data)
        if iface_check_res.status_code == 200:
            iface_check = json.loads(iface_check_res.text)
            # print("iface_check",iface_check)
            if iface_check['Result'] == 30000:
                iface_check = iface_check['Data']['iface_check']
                for item in iface_check:
                    if item['interface'] == l2tp_name:
                        if item['result'] == "success":
                            print(f"{l2tp_name}:线路检测成功")
                            return True
                        else:
                            # print(f"{l2tp_name}:线路存在，连接不成功")
                            pass
            else:
                return False
        else:
            return False

# if __name__ == '__main__':
#     ikuai = IKuai()
#     res = ikuai.insert_route_info('admin', 'lhblm520', '192.168.9.1')
#     print(res)
#
#     res = ikuai.get_cpu_info()
#
#     print(res.text)
if __name__ == '__main__':
    pass